/*
 * properties.cc
 *
 *  Created on: Dec 21, 2010
 *      Author: fify
 */

#include "properties.h"
#include <cstdlib>
#include <sstream>
#include <fstream>
#include <iostream>

namespace CncrJConfig
{

Properties * Properties::get_instance()
{
	static Properties prop;
	return &prop;
}

Properties::Properties()
{
        propmap = new std::map<std::string, std::string>;
}

Properties::~Properties()
{
        delete propmap;
}

/// 从属性文件读入属性值，存放在propmap中
int Properties::load_properties(const char* fileName, char delimiter /*='='*/,
                bool verbose/*=false*/, bool multiline /*=false*/)
{
        std::ifstream input(fileName);
        std::string line;

        if (!input.is_open())
        {
                std::cerr << "Properties::loadProperties() Could not open the file:"
                                << fileName << std::endl;
                return (-1);
        }
        load_properties(input, delimiter, verbose, multiline);
        input.close();
        return 0;
}

/**
 * ist: 属性文件
 * delimiter: 属性名和属性值分隔符
 * verbose: 是否显示属性
 * multiline: 属性的值是否可以在多行表示
 */
int Properties::load_properties(std::istream &ist, char delimiter, bool verbose,
                bool multiline /*=false*/)
{
        std::string line;

        while (ist)
        {
                getline(ist, line); //read one line at a time
                if (line.find('#') == 0)
                        continue; //ignore comments
                std::string::size_type pos = line.find(delimiter); //find the delimiter

                if (pos == line.npos)
                        continue; //ignore if no delimiter is found
                std::string key = line.substr(0, pos); // get the key
                key = remove_LT_spaces(key);
                std::string value = line.substr(pos + 1); //get the value
                value = remove_LT_spaces(value);

                if (multiline)
                        (*propmap)[key] += value; // allow properties to be spread across multiple lines
                else
                        (*propmap)[key] = value;

                if (verbose)
                        std::cout << "Loading key " << key << " with value "
                                        << (*propmap)[key] << std::endl;
        }
        return 0;
}

void Properties::set_value(const std::string key, const std::string value)
{
        (*propmap)[key] = value;
        return;
}

// 删除字符串首尾空白：\t \r \n
std::string Properties::remove_LT_spaces(std::string str)
{

        char const* delims = " \t\r\n";

        // trim leading whitespace
        std::string::size_type notwhite = str.find_first_not_of(delims);
        str.erase(0, notwhite);

        // trim trailing whitespace
        notwhite = str.find_last_not_of(delims);
        str.erase(notwhite + 1);
        return (str);
}

std::string Properties::get_value(std::string key, std::string def) const
{
        if (propmap->find(key) == propmap->end())
                return def;
        return (*propmap)[key];
}
const char* Properties::get_value(std::string key, const char* def) const
{
        if (propmap->find(key) == propmap->end())
                return def;
        return (((*propmap)[key]).c_str());
}

int Properties::get_value(std::string key, int def)
{
        if (propmap->find(key) == propmap->end())
                return def;
        return (atoi(((*propmap)[key]).c_str()));
}
long Properties::get_value(std::string key, long def)
{
        if (propmap->find(key) == propmap->end())
                return def;
        return (atoll(((*propmap)[key]).c_str()));
}

long long Properties::get_value(std::string key, long long def)
{
        if (propmap->find(key) == propmap->end())
                return def;
        return (atoll(((*propmap)[key]).c_str()));
}

double Properties::get_value(std::string key, double def)
{
        if (propmap->find(key) == propmap->end())
                return def;
        return (atof(((*propmap)[key]).c_str()));
}

void Properties::get_list(std::string &outBuf, std::string linePrefix) const
{
        std::map<std::string, std::string>::iterator iter;

        for (iter = propmap->begin(); iter != propmap->end(); iter++)
        {
                if ((*iter).first.size() > 0)
                {
                        outBuf += linePrefix;
                        outBuf += (*iter).first;
                        outBuf += '=';
                        outBuf += (*iter).second;
                        outBuf += '\n';
                }
        }

        return;
}

} // End of namespace
